//
//  MSNetworkAPI.m
//  CPManage
//
//  Created by lvho on 17/4/14.
//  Copyright © 2017年 com.jiaoshou.chen. All rights reserved.
//

#import "MSNetworkAPI.h"
#import "MSNetworkHelper.h"
#import "MSCheckNetworkStatus.h"
#import "MSCommonParamsGenerator.h"
#import "MSNetworkCache.h"
#import "MSSafeObject.h"


#define kTimeoutInterval 40
#define CustomErrorDomain @"com.MSJD.httpError"
static BOOL _isOpenLog;   // 是否已开启日志打印
static NSMutableArray *_allSessionTask;
static AFHTTPSessionManager *_sessionManager;
@interface MSNetworkAPI ()
///正在运行的网络请求数
@property (assign, nonatomic) NSInteger requestCount;


@end

@implementation MSNetworkAPI

static MSNetworkAPI *networkAPI = nil;

+ (void)initialize
{
    _sessionManager = [AFHTTPSessionManager manager];
    // 设置请求的超时时间
    _sessionManager.requestSerializer.timeoutInterval = kTimeoutInterval;
    _sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
    _sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
    // 设置服务器返回结果的类型:JSON (AFJSONResponseSerializer,AFHTTPResponseSerializer)
    _sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
    //    _sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
    _sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:
                                                                 @"application/json",
                                                                 @"text/html",
                                                                 @"text/json",
                                                                 @"text/plain",
                                                                 @"text/javascript",
                                                                 @"text/xml",
                                                                 @"image/*", nil];
    
    // 打开状态栏的等待菊花
    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
    //    _isOpenLog = YES;
}

+ (void)cancelAllRequest
{
    // 锁操作
    @synchronized(self) {
        [[self allSessionTask] enumerateObjectsUsingBlock:^(NSURLSessionTask  *_Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
            [task cancel];
        }];
        [[self allSessionTask] removeAllObjects];
    }
}


+ (void)cancelRequestWithURL:(NSString *)URL
{
    if (!URL) { return; }
    @synchronized (self) {
        [[self allSessionTask] enumerateObjectsUsingBlock:^(NSURLSessionTask  *_Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([task.currentRequest.URL.absoluteString hasPrefix:URL]) {
                [task cancel];
                [[self allSessionTask] removeObject:task];
                *stop = YES;
            }
        }];
    }
}

+ (void)openLog {
    _isOpenLog = NO;
}

+ (void)closeLog {
    _isOpenLog = NO;
}

+ (void)openNetworkActivityIndicator:(BOOL)open {
    [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:open];
}

-(void)postWithRequest:(MSLRequsetFactory *)request
         responseCache:(MSRequestCache)cacheBlock
               success:(MSRequestSuccess)success
               failure:(MSRequestFailed)failure
{
    
}

#pragma mark - GET请求无缓存
+ (NSURLSessionTask *)GET:(NSString *)path
                   domain:(NSString *)domain
               parameters:(id)parameters
                  success:(MSRequestSuccess)success
                  failure:(MSRequestFailed)failure{
    return [self GET:path domain:domain parameters:parameters needAnalisys:YES responseCache:nil success:success failure:failure];
}

+ (__kindof NSURLSessionTask *)GET:(NSString *)path
                            domain:(NSString *)domain
                        parameters:(id)parameters
                      needAnalisys:(BOOL)needAnalisys
                           success:(MSRequestSuccess)success
                           failure:(MSRequestFailed)failure {
    return [self GET:path domain:domain parameters:parameters needAnalisys:needAnalisys responseCache:nil success:success failure:failure];
}


#pragma mark - POST请求无缓存
+ (NSURLSessionTask *)POST:(NSString *)path
                    domain:(NSString *)domain
                parameters:(id)parameters
                isJsonData:(BOOL)isJson
                   success:(MSRequestSuccess)success
                   failure:(MSRequestFailed)failure {
    return [self POST:path domain:domain parameters:parameters isJsonData:isJson responseCache:nil success:success failure:failure];
}

#pragma mark - GET请求自动缓存

+ (NSURLSessionTask *)GET:(NSString *)path
                   domain:(NSString *)domain
               parameters:(id)parameters
            responseCache:(MSRequestCache)responseCache
                  success:(MSRequestSuccess)success
                  failure:(MSRequestFailed)failure {
    return [self GET:path domain:domain parameters:parameters needAnalisys:YES responseCache:responseCache success:success failure:failure];
}

+ (NSURLSessionTask *)GET:(NSString *)path
                   domain:(NSString *)domain
               parameters:(id)parameters
             needAnalisys:(BOOL)needAnalisys
            responseCache:(MSRequestCache)responseCache
                  success:(MSRequestSuccess)success
                  failure:(MSRequestFailed)failure {
    NSString *URL = [NSString stringWithFormat:@"%@%@",domain,path];
    if ([MSCommonParamsGenerator commonParams]) {
        [[MSCommonParamsGenerator commonParams] enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            [_sessionManager.requestSerializer clearAuthorizationHeader];
            if (![MSNetworkHelper isNull:key]) {
                [_sessionManager.requestSerializer setValue:obj?obj:@""
                                         forHTTPHeaderField:key];
            }
        }];
    }
    //读取缓存
    responseCache!=nil ? responseCache([MSNetworkCache httpCacheForURL:URL parameters:parameters]) : nil;
    NSURLSessionTask *sessionTask = [_sessionManager GET:URL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        [[self allSessionTask] removeObject:task];
        
        if (!needAnalisys || !responseObject[@"code"]) { // 对于返回的值没有code或者不需要解析的接口，直接返回responseObject
            success ? success(responseObject) : nil;
            return ;
        }
        //判断code = 0
        if ([responseObject[@"code"] integerValue] == 200) {
            success(responseObject);
        } else if (([responseObject[@"code"] integerValue] != 200) && ([responseObject[@"code"] integerValue] != 0)) {
            NSString *errMsg = nil;
            if ([MSSafeObject isNull:responseObject[@"msg"]]) {
                errMsg = [NSString stringWithFormat:@"未知异常 code:%@",[MSSafeObject stringInfo:responseObject[@"code"]]];
            }
            else
            {
                errMsg = responseObject[@"msg"]?:@"未知1";
            }
            
            //服务器强制退出登录code
            if ([responseObject[@"code"] integerValue] == 1001) {
                [[NSNotificationCenter defaultCenter] postNotificationName:@"Long-distanceLoginNty" object:nil];
//                [MemoryUser deleteAccount];
            }
            
            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg                                                                       forKey:NSLocalizedDescriptionKey];
            NSInteger code = -1;
            if (responseObject[@"code"]) {
                code = [responseObject[@"code"] integerValue];
            } else if (responseObject[@"err_code"]) {
                code = [responseObject[@"err_code"] integerValue];
            } else if (responseObject[@"errno"]) {
                code = [responseObject[@"errno"] integerValue];
            }
            NSError *aError = [NSError errorWithDomain:CustomErrorDomain code:code userInfo:userInfo];
            failure ? failure(aError) : nil;
            
        }else
        {
            if ([responseObject isKindOfClass:[NSDictionary class]] && ![MSSafeObject isNull:responseObject[@"data"]]) {
                responseObject = responseObject[@"data"];
                success ? success(responseObject) : nil;
            }
            else
            {
                success ? success(nil) : nil;
            }
            //对数据进行异步缓存
            responseCache!=nil ? [MSNetworkCache setHttpCache:responseObject URL:URL parameters:parameters] : nil;
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        NSHTTPURLResponse * responses = (NSHTTPURLResponse *)task.response;
        NSDictionary *userInfo = nil;
        NSInteger code = 0;
        if (responses.statusCode == 0) {
            userInfo = @{NSLocalizedDescriptionKey:@"网络错误~"};
            code = error.code;
        } else {
            userInfo = @{NSLocalizedDescriptionKey:[MSSafeObject stringInfo:[NSHTTPURLResponse localizedStringForStatusCode:responses.statusCode]]};
            code = responses.statusCode;
        }
        NSError *aError = [NSError errorWithDomain:CustomErrorDomain code:code userInfo:userInfo];
        
        failure ? failure(aError) : nil;
        
        
    }];
    // 添加sessionTask到数组
    sessionTask ? [[self allSessionTask] addObject:sessionTask] : nil ;
    
    return sessionTask;
}

#pragma mark - POST请求自动缓存
+ (NSURLSessionTask *)POST:(NSString *)path
                    domain:(NSString *)domain
                parameters:(id)parameters
                isJsonData:(BOOL)isJson
             responseCache:(MSRequestCache)responseCache
                   success:(MSRequestSuccess)success
                   failure:(MSRequestFailed)failure {
    NSString *URL = [NSString stringWithFormat:@"%@%@",domain,path];
    NSLog(@"\n POST:%@  \n parameters:%@  \n responseCache:%@",URL,parameters,responseCache);
    
    if (isJson) {
        _sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
    }
    else
    {
        _sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        parameters = ((NSDictionary *)parameters ).mutableCopy;
        [parameters addEntriesFromDictionary:[MSCommonParamsGenerator commonParams]];
    }
    //设置请求头公参
    if ([MSCommonParamsGenerator commonParams]) {
        [[MSCommonParamsGenerator commonParams] enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            [_sessionManager.requestSerializer clearAuthorizationHeader];
            if (![MSNetworkHelper isNull:key]) {
                [_sessionManager.requestSerializer setValue:obj?obj:@""
                                         forHTTPHeaderField:key];
            }
        }];
    }
    //读取缓存
    responseCache!=nil ? responseCache([MSNetworkCache httpCacheForURL:URL parameters:parameters]) : nil;
    NSURLSessionTask *sessionTask = [_sessionManager POST:URL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        if (_isOpenLog) {NSLog(@"responseObject = %@",[self jsonToString:responseObject]);}
        [[self allSessionTask] removeObject:task];
        //判断code = 0
        if ((([responseObject[@"code"] integerValue] != 200) && ([responseObject[@"code"] integerValue] != 0))) {
            NSString *errMsg = nil;
            if ([MSSafeObject isNull:responseObject[@"msg"]]) {
                errMsg = [NSString stringWithFormat:@"未知异常 code:%@",[MSSafeObject stringInfo:responseObject[@"code"]]];
            }
            else
            {
                errMsg = responseObject[@"msg"];
            }
            
            //服务器强制退出登录code
            if ([responseObject[@"code"] integerValue] == 1001) {
                [[NSNotificationCenter defaultCenter] postNotificationName:@"Long-distanceLoginNty" object:nil];
                // FIXME:
//                [MemoryUser deleteAccount];
            }
            
            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg                                                                       forKey:NSLocalizedDescriptionKey];
            NSError *aError = [NSError errorWithDomain:CustomErrorDomain code:[responseObject[@"code"] integerValue] userInfo:userInfo];
            failure ? failure(aError) : nil;
            
        } else {
            if ([responseObject isKindOfClass:[NSDictionary class]] && responseObject[@"data"]) {
                responseObject = responseObject[@"data"];
            }
            success ? success(responseObject) : nil;
            //对数据进行异步缓存
            responseCache!=nil ? [MSNetworkCache setHttpCache:responseObject URL:URL parameters:parameters] : nil;
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        NSHTTPURLResponse * responses = (NSHTTPURLResponse *)task.response;
        NSDictionary *userInfo = nil;
        NSInteger code = 0;
        if (responses.statusCode == 0) {
            userInfo = @{NSLocalizedDescriptionKey:@"网络错误~"};
            code = error.code;
        } else {
            userInfo = @{NSLocalizedDescriptionKey:[MSSafeObject stringInfo:[NSHTTPURLResponse localizedStringForStatusCode:responses.statusCode]]};
            code = responses.statusCode;
        }
        NSError *aError = [NSError errorWithDomain:CustomErrorDomain code:code userInfo:userInfo];
        
        failure ? failure(aError) : nil;
        
    }];
    
    // 添加最新的sessionTask到数组
    sessionTask ? [[self allSessionTask] addObject:sessionTask] : nil ;
    return sessionTask;
}

#pragma mark - 上传文件
+ (NSURLSessionTask *)uploadFileWithURL:(NSString *)path
                                 domain:(NSString *)domain
                             parameters:(id)parameters
                                   name:(NSString *)name
                               filePath:(NSString *)filePath
                               progress:(MSProgressBlock)progress
                                success:(MSRequestSuccess)success
                                failure:(MSRequestFailed)failure {
    NSString *URL = [NSString stringWithFormat:@"%@%@",domain,path];
    NSURLSessionTask *sessionTask = [_sessionManager POST:URL parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSError *error = nil;
        [formData appendPartWithFileURL:[NSURL URLWithString:filePath] name:name error:&error];
        (failure && error) ? failure(error) : nil;
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        //上传进度
        dispatch_sync(dispatch_get_main_queue(), ^{
            progress ? progress(uploadProgress) : nil;
        });
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        if (_isOpenLog) {NSLog(@"responseObject = %@",[self jsonToString:responseObject]);}
        [[self allSessionTask] removeObject:task];
        success ? success(responseObject) : nil;
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        if (_isOpenLog) {NSLog(@"error = %@",error);}
        [[self allSessionTask] removeObject:task];
        failure ? failure(error) : nil;
    }];
    
    // 添加sessionTask到数组
    sessionTask ? [[self allSessionTask] addObject:sessionTask] : nil ;
    
    return sessionTask;
}

#pragma mark - 上传多张图片
+ (NSURLSessionTask *)uploadImagesWithURL:(NSString *)path
                                   domain:(NSString *)domain
                               parameters:(id)parameters
                                     name:(NSString *)name
                                   images:(NSArray<UIImage *> *)images
                                fileNames:(NSArray<NSString *> *)fileNames
                               imageScale:(CGFloat)imageScale
                                imageType:(NSString *)imageType
                                 progress:(MSProgressBlock)progress
                                  success:(MSRequestSuccess)success
                                  failure:(MSRequestFailed)failure {
    NSString *URL = [NSString stringWithFormat:@"%@%@",domain,path];
    NSURLSessionTask *sessionTask = [_sessionManager POST:URL parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        
        for (NSUInteger i = 0; i < images.count; i++) {
            // 图片经过等比压缩后得到的二进制文件
            NSData *imageData = UIImageJPEGRepresentation(images[i], imageScale ?: 1.f);
            // 默认图片的文件名, 若fileNames为nil就使用
            
            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            formatter.dateFormat = @"yyyyMMddHHmmss";
            NSString *str = [formatter stringFromDate:[NSDate date]];
            NSString *imageFileName = [NSString stringWithFormat:@"%@%ld.%@",str,i,imageType?:@"jpg"];
            
            [formData appendPartWithFileData:imageData
                                        name:name
                                    fileName:fileNames ? [NSString stringWithFormat:@"%@.%@",fileNames[i],imageType?:@"jpg"] : imageFileName
                                    mimeType:[NSString stringWithFormat:@"image/%@",imageType ?: @"jpg"]];
        }
        
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        //上传进度
        dispatch_sync(dispatch_get_main_queue(), ^{
            progress ? progress(uploadProgress) : nil;
        });
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        if (_isOpenLog) {NSLog(@"responseObject = %@",[self jsonToString:responseObject]);}
        [[self allSessionTask] removeObject:task];
        success ? success(responseObject) : nil;
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        if (_isOpenLog) {NSLog(@"error = %@",error);}
        [[self allSessionTask] removeObject:task];
        failure ? failure(error) : nil;
    }];
    
    // 添加sessionTask到数组
    sessionTask ? [[self allSessionTask] addObject:sessionTask] : nil ;
    
    return sessionTask;
}

#pragma mark - 下载文件
+ (NSURLSessionTask *)downloadWithURL:(NSString *)path
                               domain:(NSString *)domain
                              fileDir:(NSString *)fileDir
                             progress:(MSProgressBlock)progress
                              success:(void(^)(NSString *))success
                              failure:(MSRequestFailed)failure {
    
    NSString *URL = [NSString stringWithFormat:@"%@%@",domain,path];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:URL]];
    __block NSURLSessionDownloadTask *downloadTask = [_sessionManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        //下载进度
        dispatch_sync(dispatch_get_main_queue(), ^{
            progress ? progress(downloadProgress) : nil;
        });
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        //拼接缓存目录
        NSString *downloadDir = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:fileDir ? fileDir : @"Download"];
        //打开文件管理器
        NSFileManager *fileManager = [NSFileManager defaultManager];
        //创建Download目录
        [fileManager createDirectoryAtPath:downloadDir withIntermediateDirectories:YES attributes:nil error:nil];
        //拼接文件路径
        NSString *filePath = [downloadDir stringByAppendingPathComponent:response.suggestedFilename];
        //返回文件位置的URL路径
        return [NSURL fileURLWithPath:filePath];
        
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        
        [[self allSessionTask] removeObject:downloadTask];
        if(failure && error) {failure(error) ; return ;};
        success ? success(filePath.absoluteString /** NSURL->NSString*/) : nil;
        
    }];
    //开始下载
    [downloadTask resume];
    // 添加sessionTask到数组
    downloadTask ? [[self allSessionTask] addObject:downloadTask] : nil ;
    
    return downloadTask;
}

/**
 *  json转字符串
 */
+ (NSString *)jsonToString:(id)data {
    if(data == nil) { return nil; }
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

/**
 存储着所有的请求task数组
 */
+ (NSMutableArray *)allSessionTask {
    if (!_allSessionTask) {
        _allSessionTask = [[NSMutableArray alloc] init];
    }
    return _allSessionTask;
}

@end
#pragma mark - NSDictionary,NSArray的分类
/*
 ************************************************************************************
 *新建NSDictionary与NSArray的分类, 控制台打印json数据中的中文
 ************************************************************************************
 */

#ifdef DEBUG
@implementation NSArray (MS)

- (NSString *)descriptionWithLocale:(id)locale {
    NSMutableString *strM = [NSMutableString stringWithString:@"(\n"];
    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        [strM appendFormat:@"\t%@,\n", obj];
    }];
    [strM appendString:@")"];
    
    return strM;
}

@end

@implementation NSDictionary (MS)

- (NSString *)descriptionWithLocale:(id)locale {
    NSMutableString *strM = [NSMutableString stringWithString:@"{\n"];
    [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        [strM appendFormat:@"\t%@ = %@;\n", key, obj];
    }];
    
    [strM appendString:@"}\n"];
    
    return strM;
}
@end
#endif

